import axios, { type InternalAxiosRequestConfig, type AxiosResponse } from "axios";
import qs from "qs";
import { useUserStoreHook } from "@/store/modules/user.store";
import { ResultCode } from "@/enums/common/result.enum";
import { getAccessToken } from "@/utils/auth";
import router from "@/router";
import guardUrl from "@/utils/guard-url";
// 创建 axios 实例
const service = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API,
  timeout: 50000,
  //headers: { "Content-Type": "application/json;charset=utf-8" },
  //paramsSerializer: (params) => qs.stringify(params),
});

// 请求拦截器
service.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    config.headers.from = 'guard'
    const accessToken = getAccessToken();
    // 如果 Authorization 设置为 no-auth，则不携带 Token
    if (config.headers.Authorization !== "no-auth" && accessToken) {
      config.headers.Authorization = `Bearer ${accessToken}`;

    } else {
      delete config.headers.Authorization;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截器
service.interceptors.response.use(
  (response: AxiosResponse) => {
    // 如果响应是二进制流，则直接返回，用于下载文件、Excel 导出等
    if (response.config.responseType === "blob") {
      return response;
    }
    const { code, msg, data,status } = response.data;
    if (status) {
        data['msg'] = msg
      return data;
    }

    ElMessage.error(msg || "系统出错");
    return Promise.reject(new Error(msg || "Error"));
  },
  async (error) => {
    // console.error("request error", error); // for debug
    const { config, response } = error;
    if (response) {
      const { code, msg } = response.data;
      if (code === ResultCode.ACCESS_TOKEN_INVALID) {
        // Session Token 过期，刷新 Token
        return handleTokenRefresh(config); // return 申请新会话token请求的Promise。
      } else if (code === ResultCode.REFRESH_TOKEN_INVALID) {
        // Refresh Token 过期，跳转登录页
        await handleRefreshTokenExpired();

        // return Promise.reject(new Error(msg || "Error"));
        //针对REFRESH_TOKEN_INVALID，我觉得这里没有必要return Promise.reject(new Error(msg || "Error"));继续抛出错误
        // 因为后继的user.stor.ts.refreshToken().catch和request.ts.handleTokenRefresh().catch目前也没有实质性处理，仅console.log
        return new Promise(() => { }); // 关键修改,返回一个永远pending的Promise，中断了Promise链,即不触发.then()也不触发.catch()，***也不触发.finally()。
      } else if (response.status === 401) {
        router.push("/401");
      } else if (response.status === 403) {
        router.push("/403");
      } else if (response.status === 404) {
        router.push("/404");
      } else if (response.status === 500) {
        //router.push("/500");
        router.push("/");
          console.log('发生了500错误，跳转到首页！')
      } else {
        ElMessage.error(msg || "系统出错");
      }
    }
    return Promise.reject(error.message);
  }
);

export default service;
// 是否正在刷新标识，避免重复刷新
let isRefreshing = false;
// 因 Token 过期导致的请求等待队列
const waitingQueue: Array<() => void> = [];
// 刷新 Token 处理
async function handleTokenRefresh(config: InternalAxiosRequestConfig) {
  return new Promise((resolve) => {
    // 封装需要重试的请求
    const retryRequest = () => {
      config.headers.Authorization = `Bearer ${getAccessToken()}`;
      resolve(service(config));
    };
    waitingQueue.push(retryRequest);
    if (!isRefreshing) {
      isRefreshing = true;
      useUserStoreHook()
        .refreshToken()
        .then(() => {
          // 依次重试队列中所有请求, 重试后清空队列
          waitingQueue.forEach((callback) => callback());
          waitingQueue.length = 0;
        })
        .catch((error) => {
          console.error("handleTokenRefresh error -->request.ts.handleTokenRefresh()", error);
          // 刷新 Token 失败，错误已在响应拦截器中处理，不用再调用handleRefreshTokenExpired()
          // return Promise.reject(error); //此处没必要再抛出错误，外层没有catch,会导致Uncaught (in promise) Error。
        })
        .finally(() => {
          isRefreshing = false;
        });
    }
  });
}
// 处理会话过期
async function handleRefreshTokenExpired() {
  ElNotification({
    title: "提示",
    message: "您的会话已过期，请重新登录",
    type: "info",
  });
  await useUserStoreHook().clearSessionAndCache();
  router.push(guardUrl.common.login);
}

